#include <gtest/gtest.h>
#include "Logger.h"
#include <filesystem>
#include <fstream>
#include <vector>
#include <thread>
#include <atomic>
#include <cctype>

namespace fs = std::filesystem;

class LoggerTest : public ::testing::Test {
protected:
    void SetUp() override {
        for (const auto& entry : fs::directory_iterator(".")) {
            if (entry.path().string().find("test_log") != std::string::npos) {
                fs::remove(entry.path());
            }
        }

        sleep(1);
        Logger::instance().init("test_log", 1000);

    }

    void TearDown() override {
        Logger::instance().shutdown();

        for (const auto& entry : fs::directory_iterator(".")) {
            if (entry.path().string().find("test_log") != std::string::npos) {
                fs::remove(entry.path());
            }
        }
    }

    int log_file_count() {
        int count = 0;
        for (const auto& entry : fs::directory_iterator(".")) {
            if (entry.path().string().find("test_log") != std::string::npos) {
                count++;
            }
        }
        return count;
    }

    std::string read_all_logs() {
        std::string content;
        for (const auto& entry : fs::directory_iterator(".")) {
            if (entry.path().string().find("test_log") != std::string::npos) {
                std::ifstream file(entry.path());
                content += std::string((std::istreambuf_iterator<char>(file)),
                                      std::istreambuf_iterator<char>());
            }
        }
        return content;
    }

    bool log_contains(const std::string& substr) {
        std::string logs = read_all_logs();
        return logs.find(substr) != std::string::npos;
    }

    int count_occurrences(const std::string& substr) {
        std::string logs = read_all_logs();
        int count = 0;
        size_t pos = 0;
        while ((pos = logs.find(substr, pos)) != std::string::npos) {
            count++;
            pos += substr.length();
        }
        return count;
    }
};

TEST_F(LoggerTest, LogSimpleMessage) {
    LOG_INFO_FMT("Test simple info message");
    LOG_WARN_FMT("Test simple info message");
    LOG_ERROR_FMT("Test simple info message");
    Logger::instance().shutdown(); // 确保消息被处理

    EXPECT_TRUE(log_contains("Test simple info message"));
    EXPECT_TRUE(log_contains("[INFO]"));
    EXPECT_TRUE(log_contains("[WARN]"));
    EXPECT_TRUE(log_contains("[ERROR]"));
}

TEST_F(LoggerTest, LogFormattedMessage) {
    short short_val = -123;
    unsigned short ushort_val = 456;
    int int_val = -123456;
    unsigned int uint_val = 123456;
    long long_val = -654321;
    unsigned long ulong_val = 654321;
    long long llong_val = -1234567890;
    unsigned long long ullong_val = 1234567890;

    float float_val = 3.14f;
    double double_val = 2.71828;

    char char_val = 'A';
    const char* cstr_val = "Hello, Logger!";
    std::string stdstr_val = "Hello, std::string!";

    void* ptr_val = reinterpret_cast<void*>(0x12345678);

    // 输出日志
    LOG_INFO_FMT("Integers: {}, {}, {}, {}, {}, {}, {}, {}",
             short_val, ushort_val, int_val, uint_val, long_val, ulong_val, llong_val, ullong_val);
    LOG_INFO_FMT("Floats: {}, {}", float_val, double_val);
    LOG_INFO_FMT("Chars: {}, {}, {}", char_val, cstr_val, stdstr_val.c_str());
    LOG_INFO_FMT("Pointer: {}", ptr_val);

    Logger::instance().shutdown();

    EXPECT_TRUE(log_contains("Integers: -123, 456, -123456, 123456, -654321, 654321, -1234567890, 1234567890"));
    EXPECT_TRUE(log_contains("Chars: A, Hello, Logger!, Hello, std::string!"));
    EXPECT_TRUE(log_contains("Pointer: 0x"));
}

TEST_F(LoggerTest, LogLevelFiltering) {
    Logger::instance().set_level(LogLevel::WARN);

    LOG_DEBUG_FMT("This debug should not appear");
    LOG_INFO_FMT("This info should not appear");
    LOG_WARN_FMT("This warning should appear");
    LOG_ERROR_FMT("This error should appear");
    Logger::instance().shutdown();

    EXPECT_FALSE(log_contains("This debug should not appear"));
    EXPECT_FALSE(log_contains("This info should not appear"));
    EXPECT_TRUE(log_contains("This warning should appear"));
    EXPECT_TRUE(log_contains("This error should appear"));
}

TEST_F(LoggerTest, FileRolling) {
    for (int i = 0; i < 100; i++) {
        LOG_INFO_FMT("This is a test message to fill up log file. Iteration: {}", i);
    }
    Logger::instance().shutdown();

    EXPECT_EQ(log_file_count(), 1);

    std::string content = read_all_logs();
    EXPECT_TRUE(content.find("Iteration: 0") != std::string::npos);
    EXPECT_TRUE(content.find("Iteration: 99") != std::string::npos);
}

TEST_F(LoggerTest, SingleThreadPerformance) {
    const int num_logs = 100;
    auto start = std::chrono::high_resolution_clock::now();

    for (int i = 0; i < num_logs; i++) {
        LOG_INFO_FMT("Performance test message {}", i);
    }
    auto submit_end = std::chrono::high_resolution_clock::now();
    Logger::instance().shutdown();
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

    std::cout << "Submit Logged " << num_logs << " messages in " << std::chrono::duration_cast<std::chrono::milliseconds>(submit_end - start).count() << " ms\n";
    std::cout << "Logged " << num_logs << " messages in " << duration << " ms\n";
    std::cout << "Throughput: " << (num_logs * 1000.0 / duration) << " logs/sec\n";

    EXPECT_EQ(count_occurrences("Performance test message"), num_logs);
}

int main(int argc, char** argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}